package examples;


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;



/**
  * Java Neural Network Example
  * Handwriting Recognition
  * by Jeff Heaton (http://www.jeffheaton.com) 1-2002
  * -------------------------------------------------
  * This class presents the main application window.
  *
  * @author Jeff Heaton (http://www.jeffheaton.com)
  * @version 1.0
  *

  */

public class MainEntry extends JFrame implements Runnable {

   /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final double ERROR_PERMITIDO_AL_RECONOCER = 15;

/**
    * The downsample width for the application.
    */
   static final int DOWNSAMPLE_WIDTH = 30;
   static final String PATH = "files/";
   static final String NOMBRE_ARCH = "numeros2";

   /**
    * The down sample height for the application.
    */
   static final int DOWNSAMPLE_HEIGHT = 50;

   /**
    * The entry component for the user to draw into.
    */
   Entry entry;

   /**
    * The current down sample component to display the drawing
    * downsampled.
    */
   Sample currentSample;
   
   /**
    * A list of samples
    */
   List<Sample> samples;
   
   /**
    * The iterator of samples
    */
   Iterator<Sample> sampleIterator;

   /**
    * The figures that have been defined.
    */
   DefaultListModel letterListModel = new DefaultListModel();
   
   /**
    * The figures that have been defined in the second network.
    */
//   DefaultListModel letterListModelOptimized = new DefaultListModel();

   /**
    * The neural network.
    */
   KohonenNetwork net;
   
   /**
    * The second neural network.
    */
//   KohonenNetwork netOptimized;

   /**
    * The background thread used for training.
    */
   Thread trainThread = null;

   /**
    * The constructor.
    */
   @SuppressWarnings("deprecation")
MainEntry()
   {
	  
     entry = new Entry();
     entry.reshape(168,25,200,128);
     initSamples();
    
     //{{INIT_CONTROLS
     setTitle("Tp Promocion");
     getContentPane().setLayout(new GridLayout(2,1));
     
     JPanel p1 = new JPanel (new BorderLayout());
     JPanel p2 = new JPanel (new BorderLayout());
   
     
     //3
     JLabel2.setBounds(12,264,72,24);
     downSample.setText("Down Sample");
     downSample.setActionCommand("Down Sample");

     
     
     //Panel 2
     add.setText("Agregar");
     add.setActionCommand("Agregar");
     imagen.setText("Cargar Imagen");
     imagen.setActionCommand("Cargar Imagen");
     imagen.addActionListener(getImageSelectAction());
     clear.setText("Borrar");
     clear.setActionCommand("Borrar");
     recognize.setText("Reconocer");
     recognize.setActionCommand("Reconocer");
     JLabel5.setText("Area de Dibujo");
     JPanel pentry = new JPanel (new BorderLayout());
     pentry.add(JLabel5,BorderLayout.NORTH);
     pentry.add(entry,BorderLayout.CENTER);
     
     JPanel pbotones = new JPanel (new FlowLayout ());
     pbotones.add(add);
     pbotones.add(imagen);
     pbotones.add(clear);
     pbotones.add(recognize);
     pentry.add(pbotones,BorderLayout.SOUTH);
     pbotones.setBackground(Color.black);
     
     pentry.add(JLabel5,BorderLayout.NORTH);
     p2.add(pentry);
     
     //Panel 1 
     JLabel1.setText("Diccionario");
     JScrollPane1.setVerticalScrollBarPolicy(
       javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
     JScrollPane1.setOpaque(true);
     JScrollPane1.getViewport().add(letters);
     del.setText("Borrar");
     del.setActionCommand("Borrar");
     load.setText("Cargar Archivo");
     load.setActionCommand("Cargar Archivo");
     save.setText("Guardar Archivo");
     save.setActionCommand("Guardar Archivo");
     train.setText("Entrenar Red");
     train.setActionCommand("Entrenar Red");
         
     JPanel pdicc = new JPanel (new BorderLayout());
     JPanel pbotones2 = new JPanel (new BorderLayout());
     
     pdicc.add(JScrollPane1,BorderLayout.CENTER);
     pdicc.add(JLabel1,BorderLayout.NORTH);
     pdicc.add(pbotones2,BorderLayout.SOUTH);
     
     pbotones2.add(del,BorderLayout.NORTH);
     pbotones2.add(load,BorderLayout.WEST);
     pbotones2.add(save,BorderLayout.EAST);
     pbotones2.add(train,BorderLayout.SOUTH);
     
     p1.add(pdicc);
     

     //{{REGISTER_LISTENERS
     SymAction lSymAction = new SymAction();
     downSample.addActionListener(lSymAction);
     clear.addActionListener(lSymAction);
     add.addActionListener(lSymAction);
     del.addActionListener(lSymAction);
    
     SymListSelection lSymListSelection = new SymListSelection();
     letters.addListSelectionListener(lSymListSelection);
     load.addActionListener(lSymAction);
     save.addActionListener(lSymAction);
     train.addActionListener(lSymAction);
     recognize.addActionListener(lSymAction);
     //}}
     letters.setModel(letterListModel);
     //{{INIT_MENUS
     //}}
     
     
     
     
     getContentPane().add(p1);
     getContentPane().add(p2);
   
     setSize(600,600);
     setVisible(false);
     
   }

   protected void initSamples(){
	   	 samples = new ArrayList<Sample>();
	     sampleIterator = samples.iterator();
	     currentSample = new Sample(DOWNSAMPLE_WIDTH,DOWNSAMPLE_HEIGHT);
	     
	     samples.add(currentSample);
	     entry.setSamples(samples);
	     
   }

   /**
    * The main method.
    *
    * @param args Args not really used.
    */

public static void main(String args[])
   {
	  final MainEntry mainEntry= new MainEntry();
	  mainEntry.setVisible(true);
	   WindowListener wndListenEvt = new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				mainEntry.setVisible(false);
				System.exit(0);
			}
		};
		mainEntry.addWindowListener(wndListenEvt);
   
   }
   //{{DECLARE_CONTROLS
   javax.swing.JLabel JLabel1 = new javax.swing.JLabel();
   javax.swing.JLabel JLabel2 = new javax.swing.JLabel();

   /**
    * THe downsample button.
    */
   javax.swing.JButton downSample = new javax.swing.JButton();

   /**
    * The add button.
    */
   javax.swing.JButton add = new javax.swing.JButton();

   /**
    * The clear button
    */
   javax.swing.JButton clear = new javax.swing.JButton();
   
   /**
    * Agregar Imagen para reconocer
    */
   javax.swing.JButton imagen= new javax.swing.JButton();
   
   /**
    * The recognize button
    */
   javax.swing.JButton recognize = new javax.swing.JButton();
   javax.swing.JScrollPane JScrollPane1 = new javax.swing.JScrollPane();

   /**
    * The letters list box
    */
   javax.swing.JList letters = new javax.swing.JList();

   /**
    * The delete button
    */
   javax.swing.JButton del = new javax.swing.JButton();

   /**
    * The load button
    */
   javax.swing.JButton load = new javax.swing.JButton();

   /**
    * The save button
    */
   javax.swing.JButton save = new javax.swing.JButton();

   /**
    * The train button
    */
   javax.swing.JButton train = new javax.swing.JButton();
   javax.swing.JLabel JLabel3 = new javax.swing.JLabel();
   javax.swing.JLabel JLabel4 = new javax.swing.JLabel();
   
   /**
    * The test button
    */
   javax.swing.JButton test = new javax.swing.JButton();
   javax.swing.JLabel JLabel6 = new javax.swing.JLabel();

   /**
    * How many tries
    */
   javax.swing.JLabel tries = new javax.swing.JLabel();

   /**
    * The last error
    */
   javax.swing.JLabel lastError = new javax.swing.JLabel();

   /**
    * The best error
    */
   javax.swing.JLabel bestError = new javax.swing.JLabel();
   javax.swing.JLabel JLabel8 = new javax.swing.JLabel();
   javax.swing.JLabel JLabel5 = new javax.swing.JLabel();
   
   /**
    * The next button
    */
   javax.swing.JButton next = new javax.swing.JButton();
   //}}
   //{{DECLARE_MENUS
   //}}

   class SymAction implements java.awt.event.ActionListener {
     public void actionPerformed(java.awt.event.ActionEvent event)
     {
       Object object = event.getSource();
       if ( object == downSample )
         downSample_actionPerformed(event);
       else if ( object == clear )
         clear_actionPerformed(event);
       else if ( object == add )
         add_actionPerformed(event,letterListModel);
       else if ( object == del )
         del_actionPerformed(event);
       else if ( object == load ){
         load_actionPerformed(event, letterListModel,NOMBRE_ARCH+".dat");

       }
       else if ( object == save )
         save_actionPerformed(event,NOMBRE_ARCH+".dat",letterListModel);
       else if ( object == train )
         train_actionPerformed(event);
       else if ( object == recognize )
         recognize_actionPerformed(event);
       else if ( object == test )
           test_actionPerformed(event,"test.dat");
       else if ( object == next )
           next_actionPerformed(event);
     }
   }

   /**
    * Called to downsample the image.
    *
    * @param event The event
    */
   void downSample_actionPerformed(java.awt.event.ActionEvent event)
   {
     entry.downSample();

   }

   /**
    * Called to clear the image.
    *
    * @param event The event
    */
   void clear_actionPerformed(java.awt.event.ActionEvent event)
   {
     entry.clear();
     initSamples();
     currentSample.repaint();

   }

   /**
    * Called to add the current image to the training set
    *
    * @param event The event
    */
   void add_actionPerformed(java.awt.event.ActionEvent event, DefaultListModel letterListModel)
   {
  

     String letter = JOptionPane.showInputDialog(
       "Por favor ingrese los nombres de los numeros o simbolos (coma) que dibujo (separados por comas): ");
     if ( letter==null )
       return;

     entry.downSample();
     //TODO validar cantidad de down samples sea igual a letters separados por comas
     
     for (Iterator<Sample> iterator = entry.getSamples().iterator(); iterator.hasNext();) {
		Sample sample = (Sample) iterator.next();
		
		//TODO separar el string y asignar a cada sample el correspondiente
		SampleData sampleData = (SampleData)sample.getData().clone();
	    sampleData.setLetter(letter);
	    letterListModel.add(letterListModel.size(),sampleData);
	}



     letters.setSelectedIndex(letterListModel.getSize()-1);
     entry.clear();
     currentSample.repaint();

   }

   /**
    * Called when the del button is pressed.
    *
    * @param event The event.
    */
   void del_actionPerformed(java.awt.event.ActionEvent event)
   {
     int i = letters.getSelectedIndex();

     if ( i==-1 ) {
       JOptionPane.showMessageDialog(this,
                                     "Por favor seleccione la figura a borrar.","Error",
                                     JOptionPane.ERROR_MESSAGE);
       return;
     }

     letterListModel.remove(i);
   }

   class SymListSelection implements javax.swing.event.ListSelectionListener {
     public void valueChanged(javax.swing.event.ListSelectionEvent event)
     {
       Object object = event.getSource();
       if ( object == letters )
         letters_valueChanged(event);
     }
   }

   /**
    * Called when a letter is selected from the list box.
    *
    * @param event The event
    */
   void letters_valueChanged(javax.swing.event.ListSelectionEvent event)
   {
     if ( letters.getSelectedIndex()==-1 )
       return;
     SampleData selected =
       (SampleData)letterListModel.getElementAt(letters.getSelectedIndex());
     currentSample.setData((SampleData)selected.clone());
     currentSample.repaint();
     entry.clear();

   }

   /**
    * Called when the load button is pressed.
    *
    * @param event The event
    */
   void load_actionPerformed(java.awt.event.ActionEvent event, DefaultListModel letterListModel,String arch)
   {
     try {
       FileReader f;// the actual file stream
       BufferedReader r;// used to read the file line by line
       f = new FileReader( new File(PATH+arch) );
       r = new BufferedReader(f);
       String line;
       int i=0;

       letterListModel.clear();

       while ( (line=r.readLine()) !=null ) {
    	   StringTokenizer tokenizer= new StringTokenizer(line,":");
    	  
         SampleData ds =new SampleData(tokenizer.nextToken(),MainEntry.DOWNSAMPLE_WIDTH,MainEntry.DOWNSAMPLE_HEIGHT); 
    	   String serieBits=tokenizer.nextToken();
         letterListModel.add(i++,ds);
         int idx=0;
         for ( int y=0;y<ds.getHeight();y++ ) {
           for ( int x=0;x<ds.getWidth();x++ ) {
             ds.setData(x,y,serieBits.charAt(idx++)=='1');
           }
         }
       }

       r.close();
       f.close();
       clear_actionPerformed(null);
       JOptionPane.showMessageDialog(this,
                                     "Cargando de '"+arch+"'.","Training",
                                     JOptionPane.PLAIN_MESSAGE);

     } catch ( Exception e ) {
    	 e.printStackTrace();
       JOptionPane.showMessageDialog(this,
                                     "Error: " + e,"Training",
                                     JOptionPane.ERROR_MESSAGE);
     }

   }

   private ActionListener getImageSelectAction()
   {
       return new ActionListener()
       {
    	   @Override
           public void actionPerformed(ActionEvent e)
           {
               JFileChooser chooser = new JFileChooser(new File("/home/$USER"));
               chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
               Set<String> filters= new HashSet<String>();
               filters.add("jpg");
               filters.add("png");
               filters.add("PNG");
               filters.add("JPG");
               FiltroImagenes filter1 = new FiltroImagenes(filters);
               chooser.setFileFilter(filter1);
               int returnVal = chooser.showOpenDialog(null);
               if (returnVal == JFileChooser.APPROVE_OPTION)
               {
                   entry.initImage(chooser.getSelectedFile());
               }
           }
		
       };
   }
   
   /**
    * Called when the save button is clicked.
    *
    * @param event The event
    */
   void save_actionPerformed(java.awt.event.ActionEvent event,String arch,DefaultListModel letterListModel)
   {
     try {
       OutputStream os;// the actual file stream
       PrintStream ps;// used to read the file line by line
       os = new FileOutputStream( PATH+arch,false );
       ps = new PrintStream(os);

       for ( int i=0;i<letterListModel.size();i++ ) {
         SampleData ds = (SampleData)letterListModel.elementAt(i);
         ps.print( ds.getLetter() + ":" );
         for ( int y=0;y<ds.getHeight();y++ ) {
           for ( int x=0;x<ds.getWidth();x++ ) {
             ps.print( ds.getData(x,y)?"1":"0" );
           }
         }
         ps.println("");
       }

       ps.close();
       os.close();
       clear_actionPerformed(null);
       JOptionPane.showMessageDialog(this,
                                     "Guardado en  '"+arch+"' .",
                                     "Training",
                                     JOptionPane.PLAIN_MESSAGE);

     } catch ( Exception e ) {
    	 e.printStackTrace();
       JOptionPane.showMessageDialog(this,"Error: " +
                                     e,"Training",
                                     JOptionPane.ERROR_MESSAGE);
     }

   }

   /**
    * Run method for the background training thread.
    */
   public void run()
   {
	   net= entrenar( letterListModel,1);

   }
public KohonenNetwork entrenar( DefaultListModel letterListModel,int numeroDeRed){
	KohonenNetwork net = null;
    try {
      int inputNeuron = MainEntry.DOWNSAMPLE_HEIGHT*
        MainEntry.DOWNSAMPLE_WIDTH;
      int outputNeuron = letterListModel.size();


      TrainingSet set = new TrainingSet(inputNeuron,outputNeuron);
      set.setTrainingSetCount(letterListModel.size());

      for ( int t=0;t<letterListModel.size();t++ ) {
        int idx=0;
        SampleData ds = (SampleData)letterListModel.getElementAt(t);
        for ( int y=0;y<ds.getHeight();y++ ) {
          for ( int x=0;x<ds.getWidth();x++ ) {
            set.setInput(t,idx++,ds.getData(x,y)?.5:-.5);
          }
        }
      }

      net = new KohonenNetwork(inputNeuron,outputNeuron,this);
      net.setTrainingSet(set);
      net.setNumeroDeRed(numeroDeRed);
      net.learn();
    } catch ( Exception e ) {
   	 e.printStackTrace();
      JOptionPane.showMessageDialog(this,"Error: " + e,
                                    "Entrenando",
                                    JOptionPane.ERROR_MESSAGE);
    }
   return net;
  
}
   /**
    * Called to update the stats, from the neural network.
    *
    * @param trial How many tries.
    * @param error The current error.
    * @param best The best error.
    */
   void updateStats(long trial,double error,double best,KohonenNetwork net)
   {
     if ( (((trial%100)!=0) || (trial==10)) && !net.halt )
       return;

     if ( net.halt ) {
       trainThread = null;
       train.setText("Empezar el entrenamiento");
       JOptionPane.showMessageDialog(this,
                                     "Ha terminado el entrenamineto de la red "+net.getNumeroDeRed(),"Entrenando",
                                     JOptionPane.PLAIN_MESSAGE);
     }
     UpdateStats stats = new UpdateStats();
     stats._tries = trial;
     stats._lastError=error;
     stats._bestError=best;
     try {
       SwingUtilities.invokeAndWait(stats);
     } catch ( Exception e ) {
    	 e.printStackTrace();
       JOptionPane.showMessageDialog(this,"Error: " + e,"Training",
                                     JOptionPane.ERROR_MESSAGE);
     }
   }

   /**
    * Called when the train button is pressed.
    *
    * @param event The event.
    */
   void train_actionPerformed(java.awt.event.ActionEvent event)
   {
     if ( trainThread==null ) {
       train.setText("Parar entrenamiento");
       train.repaint();
       trainThread = new Thread(this);
       trainThread.start();
     } else {
       net.halt=true;
//       netOptimized.halt=true;
     }
   }
   
   /**
    * Called when the next button is pressed.
    *
    * @param event The event.
    */
   void next_actionPerformed(java.awt.event.ActionEvent event)
   {
     if (!sampleIterator.hasNext()) {
       sampleIterator = samples.iterator();
     } 
     initSamples();
     currentSample.repaint();
   }

   /**
    * Called when the recognize button is pressed.
    *
    * @param event The event.
    */
   void recognize_actionPerformed(java.awt.event.ActionEvent event)
   {
	   initSamples();
     if ( net==null ) {
       JOptionPane.showMessageDialog(this,
                                     "Se necesita entrenar primero la red !","Error",
                                     JOptionPane.ERROR_MESSAGE);
       return;
     }
     entry.downSample();
     sampleIterator = samples.iterator();
     String finalNumber = new String();
     for (Iterator<Sample> iterator = samples.iterator(); iterator.hasNext();) {
    	 Sample sample = (Sample) iterator.next();
    	 double input[] = new double[DOWNSAMPLE_WIDTH*DOWNSAMPLE_HEIGHT];
    	 int idx=0;
    	 SampleData ds = sample.getData();
    	 for ( int y=0;y<ds.getHeight();y++ ) {
    		 for ( int x=0;x<ds.getWidth();x++ ) {
    			 input[idx++] = ds.getData(x,y)?.5:-.5;
    		 }
    	 }

    	 double normfac[] = new double[1];
    	 double synth[] = new double[1];
    	 net.setDebug(true);
    	 int best = net.winner ( input , normfac , synth ) ;
    	 net.setDebug(false);
    	 System.out.println("Neurona Ganadora:" +best);
    	 String map[];
    	 BigDecimal error=new BigDecimal((1-net.getRecognizeError())*100);
    	 //si el error es mayor que el 15% va a la otra red
    	 //     if(error.compareTo(new BigDecimal(ERROR_PERMITIDO_AL_RECONOCER))==-1){
    	 System.out.println("con un Error de  :" +error.setScale(2, RoundingMode.HALF_UP));
    	 System.out.println("Por red 1");
    	 System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
    	 map = mapNeurons(letterListModel,net);
    
    	 
    	finalNumber+=convertToNumberString(map[best]);
    	
     }
     JOptionPane.showMessageDialog(this,
			 "  El numero es: " + finalNumber,"Resultado",
					 JOptionPane.PLAIN_MESSAGE);
   }
   
   protected String convertToNumberString(String number){
	   
	   if (number.compareTo("Cero")==0)
		   return "0";
	   else if (number.compareTo("Uno")==0)
		   return "1";
	   else if (number.compareTo("Dos")==0)
		   return "2";
	   else if (number.compareTo("Tres")==0)
		   return "3";
	   else if (number.compareTo("Cuatro")==0)
		   return "4";
	   else if (number.compareTo("Cinco")==0)
		   return "5";
	   else if (number.compareTo("Seis")==0)
		   return "6";
	   else if (number.compareTo("Siete")==0)
		   return "7";
	   else if (number.compareTo("Ocho")==0)
		   return "8";
	   else if (number.compareTo("Nueve")==0)
		   return "9";
	   else if (number.compareTo(".")==0)
		   return ".";
	   else if (number.compareTo(",")==0)
		   return ",";
	   else   return number;
		   
   }
   /**
    * Called when the test button is pressed.
    *
    * @param event The event.
    */
   void test_actionPerformed(java.awt.event.ActionEvent event,String arch)
   {
	   if ( net==null ) {
		   JOptionPane.showMessageDialog(this,
				   "Se necesita entrenar primero la red !","Error",
				   JOptionPane.ERROR_MESSAGE);
		   return;
	   }

	   try {
		   FileReader f;// the actual file stream
		   BufferedReader r;// used to read the file line by line
		   f = new FileReader( new File(PATH+arch) );
		   r = new BufferedReader(f);
		   String line;
		   int i=0;

		   DefaultListModel testLetterListModel = new DefaultListModel();
		   Integer win=0;
		   Integer loss=0;
		   BigDecimal winPerformance =new BigDecimal(0.0);

		   while ( (line=r.readLine()) !=null ) {
			   StringTokenizer tokenizer= new StringTokenizer(line,":");

			   SampleData ds =new SampleData(tokenizer.nextToken(),MainEntry.DOWNSAMPLE_WIDTH,MainEntry.DOWNSAMPLE_HEIGHT); 
			   String serieBits=tokenizer.nextToken();
			   testLetterListModel.add(i++,ds);
			   int idx=0;
			   for ( int y=0;y<ds.getHeight();y++ ) {
				   for ( int x=0;x<ds.getWidth();x++ ) {
					   ds.setData(x,y,serieBits.charAt(idx++)=='1');
				   }
			   }
			   double input[] = new double[DOWNSAMPLE_WIDTH*DOWNSAMPLE_HEIGHT];
			   idx=0;
			   for ( int y=0;y<ds.getHeight();y++ ) {
				   for ( int x=0;x<ds.getWidth();x++ ) {
					   input[idx++] = ds.getData(x,y)?.5:-.5;
				   }
			   }

			   double normfac[] = new double[1];
			   double synth[] = new double[1];
			   //primero busca en la primera red
			   int best = net.winner ( input , normfac , synth ) ;
			   BigDecimal error=new BigDecimal((1-net.getRecognizeError())*100);
			   String map[];

				   map = mapNeurons(letterListModel,net);

			   System.out.println("La figura numero " + i + " es: "+ map[best] + " con error del: " +error.setScale(2, RoundingMode.HALF_UP));
			   if ((1-net.getRecognizeError())*100 <= ERROR_PERMITIDO_AL_RECONOCER){
				   win += 1;
			   }else{
				   loss += 1;
			   }
		   }

		   r.close();
		   f.close();
		   clear_actionPerformed(null);
		   winPerformance = new BigDecimal(win.doubleValue() / (win.doubleValue()+loss.doubleValue()));

		   JOptionPane.showMessageDialog(this,
				   "Performance: " + winPerformance.setScale(3, RoundingMode.HALF_UP),"Resultado",
				   JOptionPane.PLAIN_MESSAGE);
		   return;

	   } catch ( Exception e ) {
		   e.printStackTrace();
		   JOptionPane.showMessageDialog(this,
				   "Error: " + e,"Carga archivo de test",
				   JOptionPane.ERROR_MESSAGE);
	   }

	   clear_actionPerformed(null);
	   JOptionPane.showMessageDialog(this,
			   "Test Ejecutado","Test",
			   JOptionPane.PLAIN_MESSAGE);

	   return;

   }

   /**
    * Used to map neurons to actual letters.
    *
    * @return The current mapping between neurons and letters as an array.
    */
   String []mapNeurons( DefaultListModel letterListModel, KohonenNetwork net)
   {
	   String map[] = new String[letterListModel.size()];
     double normfac[] = new double[1];
     double synth[] = new double[1];

     for ( int i=0;i<map.length;i++ )
       map[i]="?";
     for ( int i=0;i<letterListModel.size();i++ ) {
    	 double input[] = new double[DOWNSAMPLE_WIDTH*DOWNSAMPLE_HEIGHT];
       int idx=0;
       SampleData ds = (SampleData)letterListModel.getElementAt(i);
       for ( int y=0;y<ds.getHeight();y++ ) {
         for ( int x=0;x<ds.getWidth();x++ ) {
           input[idx++] = ds.getData(x,y)?.5:-.5;
         }
       }

       int best = net.winner ( input , normfac , synth ) ;
       map[best] = ds.getLetter();
     }
     return map;
   }


   public class UpdateStats implements Runnable {
     long _tries;
     double _lastError;
     double _bestError;

     public void run()
     {
       tries.setText(""+_tries);
       lastError.setText(""+_lastError);
       bestError.setText(""+_bestError);
     }
   }


}